/**********************************************************************
 * Filename: CalendarDate.java
 * Created: 2012/04/30
 * @author Fernando Brito e Abreu
 **********************************************************************/
package org.bunny.businessLayer;

import java.util.Set;
import java.util.HashSet;

public class CalendarDate{
	public static Set<CalendarDate> allInstances = new HashSet<CalendarDate>();

	private int day;
	private int month;
	private int year;

	/**********************************************************************
	 * Default constructor
	 **********************************************************************/
	public CalendarDate(){
		allInstances.add(this);//
	}

	/**********************************************************************
	 * Parameterized constructor
	 * @param day the day to initialize
	 * @param month the month to initialize
	 * @param year the year to initialize
	 **********************************************************************/
	public CalendarDate(int day, int month, int year){
		this.day = day;
		this.month = month;
		this.year = year;
		allInstances.add(this);
	}

	public void destroy(){
		allInstances.remove(this);
	}

	/**********************************************************************
	 * Standard attribute getter
	 * @return the day of the calendarDate
	 **********************************************************************/
	public int day(){
		return day;
	}

	/**********************************************************************
	 * Standard attribute setter
	 * @param day the day to set
	 **********************************************************************/
	public void setDay(int day){
		this.day = day;
	}

	/**********************************************************************
	 * Standard attribute getter
	 * @return the month of the calendarDate
	 **********************************************************************/
	public int month(){
		return month;
	}

	/**********************************************************************
	 * Standard attribute setter
	 * @param month the month to set
	 **********************************************************************/
	public void setMonth(int month){
		this.month = month;
	}

	/**********************************************************************
	 * Standard attribute getter
	 * @return the year of the calendarDate
	 **********************************************************************/
	public int year(){
		return year;
	}

	/**********************************************************************
	 * Standard attribute setter
	 * @param year the year to set
	 **********************************************************************/
	public void setYear(int year){
		this.year = year;
	}

	/**********************************************************************
	 * User-defined operation specified in SOIL/OCL
	 **********************************************************************/
	public void adicionaDia(){
		int dia,mes, ano;

		dia = this.day;
		mes = this.month;
		ano = this.year;

		if (mes == 12 && dia == 31){
			dia = 1;
			mes = 1;
			ano++;
		}
		else{
			if(dia==31 && (mes==1 || 
					mes==3 || 
					mes==5 || 
					mes==7 || 
					mes==8 || 
					mes==10)){
				mes++;
				dia =1;
			}
			else{
				if(dia==30 && (mes==4 || mes ==6 || mes==9 || mes == 11)){
					dia=1;
					mes++;
				}
				else{
					if(dia==28 && mes==2){
						dia=1;
						mes=3;
					}
					else{
						dia++;
					}
				}
			}
		}
		this.day = dia;
		this.month=mes;
		this.year=ano;

		//	dia := self.day;
		//	 mes := self.month;
		//	 ano := self.year;
		//	 if ((mes = 12) and (dia = 31)) then self.month := (1 + mes);
		//	 self.day := 1;
		//	 self.month := 1 else if ((dia = 31) and (((((((mes = 1) or (mes = 3)) or (mes = 5)) or (mes = 7)) or (mes = 8)) or (mes = 10)) or (mes = 12))) then self.month := (mes + 1);
		//	 self.day := 1 else if ((dia = 30) and ((((mes = 4) or (mes = 6)) or (mes = 9)) or (mes = 11))) then self.day := 1;
		//	 self.month := (mes + 1) else if ((dia = 28) and (mes = 2)) then self.day := 1;
		//	 self.month := 3 else self.day := (dia + 1) end end end end;
	}

	/**********************************************************************
	 * User-defined operation specified in SOIL/OCL
	 **********************************************************************/
	public boolean dataDentroParametros(){
		//	return if ((((((self.day > 0) and (self.day <= 31)) and (self.month > 0)) and (self.month <= 12)) and (self.year > 1900)) and (self.year < 9999)) then true else false endif
		return this.day >0 && this.day <= 31 && 
				this.month >0 && 
				this.month <= 12 && 
				this.year >1900 && 
				this.year < 9999;
	}

	/**********************************************************************
	 * User-defined operation specified in SOIL/OCL
	 * @param t the t to set
	 **********************************************************************/
	public boolean dataInicializada(CalendarDate t){
		//	return if t.isDefined then true else false endif
		return t != null;
	}

	/**********************************************************************
	 * User-defined operation specified in SOIL/OCL
	 * @param day the day to set
	 * @param month the month to set
	 * @param year the year to set
	 **********************************************************************/
	public void init(int day, int month, int year){
		this.day = day;
		this.month = month;
		this.year = year;
		//	self.day := day;
		//	 self.month := month;
		//	 self.year := year;
	}

	//	PRE-CONDITIONS (TODO)
	/*
	pre DataDefinida
		((day.isDefined and month.isDefined) and year.isDefined)

	 */

	//	POST-CONDITIONS (TODO)
	/*
	post DataFoiInicializada
		((self.day.isDefined and self.month.isDefined) and self.year.isDefined)

	 */

	/**********************************************************************
	 * User-defined operation specified in SOIL/OCL
	 * @param date the date to set
	 **********************************************************************/
	public void initS(String date){
		this.day = Integer.parseInt((date.substring(0,2)));
		this.month = Integer.parseInt((date.substring(3, 5)));
		this.year = Integer.parseInt((date.substring(6, 10)));
		//	self.year := date.substring(1,4).toInteger;
		//	 self.month := date.substring(6,7).toInteger;
		//	 self.day := date.substring(9,10).toInteger;
	}

	//	PRE-CONDITIONS (TODO)
	/*
	pre StringDateDefinida
		(date.isDefined and (date.size = 10))

	 */

	//	POST-CONDITIONS (TODO)
	/*
	post DataFoiInicializadaS
		((self.day.isDefined and self.month.isDefined) and self.year.isDefined)

	 */

	/**********************************************************************
	 * User-defined operation specified in SOIL/OCL
	 * @param t the t to set
	 **********************************************************************/
	public boolean isAfter(CalendarDate t){
		if(this.year == t.year()){
			if(this.month == t.month()){
				return this.day >t.day();
			}
			else{
				return this.month > t.month();
			}
		}
		else{
			return this.year > t.year();
		}
		//	return if (self.year = t.year) then if (self.month = t.month) then (self.day > t.day) else (self.month > t.month) endif else (self.year > t.year) endif
	}

	//	PRE-CONDITIONS (TODO)
	/*
	pre CalendarDateFoiInicializada2
		self.dataInicializada(t)

	 */

	/**********************************************************************
	 * User-defined operation specified in SOIL/OCL
	 * @param t the t to set
	 **********************************************************************/
	public boolean isBefore(CalendarDate t){
		if(this.year == t.year()){
			if(this.month == t.month()){
				return this.day <t.day();
			}
			else{
				return this.month < t.month();
			}
		}
		else{
			return this.year < t.year();
		}
		//	return if (self.year = t.year) then if (self.month = t.month) then (self.day < t.day) else (self.month < t.month) endif else (self.year < t.year) endif
	}

	//	PRE-CONDITIONS (TODO)
	/*
	pre CalendarDateFoiInicializada1
		self.dataInicializada(t)

	 */

	/**********************************************************************
	 * User-defined operation specified in SOIL/OCL
	 * @param x the x to set
	 * @param y the y to set
	 **********************************************************************/
	public boolean isDivisible(int x, int y){
		//	return (((x div y) * y) = x)
		return ((Integer)(x/y))*y == x;
	}

	//	PRE-CONDITIONS (TODO)
	/*
	pre ValoresForamInicializados
		(x.isDefined and y.isDefined)

	 */

	/**********************************************************************
	 * User-defined operation specified in SOIL/OCL
	 * @param t the t to set
	 **********************************************************************/
	public boolean isEqual(CalendarDate t){
		//	return (((self.year = t.year) and (self.month = t.month)) and (self.day = t.day))
		return this.year == t.getYear() && this.month == t.getMonth() && this.day == t.getDay();
	}

	//	PRE-CONDITIONS (TODO)
	/*
	pre CalendarDateFoiInicializada3
		self.dataInicializada(t)

	 */

	public int getDay() {
		return day;
	}

	public int getMonth() {
		return month;
	}

	public int getYear() {
		return year;
	}

	/**********************************************************************
	 * User-defined operation specified in SOIL/OCL
	 **********************************************************************/
	public boolean isLeap(){
		if(this.isDivisible(this.year, 400)){
			return true;
		}
		else{
			if (this.isDivisible(this.year, 100)){
				return false;
			} 
			else{
				if (this.isDivisible(this.year, 4)){
					return true;
				}
				else{
					return false;
				}
			} 
		}
		//	return if (self.isDivisible(self.year, 400) or self.isDivisible(self.year, 4)) then true else if self.isDivisible(self.year, 100) then false else if self.isDivisible(self.year, 4) then true else false endif endif endif
	}

	/**********************************************************************
	 * User-defined operation specified in SOIL/OCL
	 * @param date the date to set
	 **********************************************************************/
	public void stringToDate(String date){
		String dia, mes,ano;
		dia = date.substring(0,2);
		mes = date.substring(3,5);
		ano = date.substring(6,10);
		//	date_year := date.substring(1,4);
		//	 date_month := date.substring(6,7);
		//	 date_day := date.substring(9,10);
		//	 result := CalendarDate.allInstances->select(cd : CalendarDate | (((cd.year = date_year.toInteger) and (cd.month = date_month.toInteger)) and (cd.day = date_day.toInteger)))->asSequence->first;
		//	 if result.isUndefined then result := new CalendarDate(((('D' + date_year) + date_month) + date_day));
		//	 result.initS(date) end;
		this.day=Integer.parseInt(dia);
		this.month =Integer.parseInt(mes);
		this.year = Integer.parseInt(ano);
		
	}

	//	PRE-CONDITIONS (TODO)
	/*
	pre StringDateFoiInicializadaS2D
		(date.isDefined and (date.size = 10))

	 */

	/**********************************************************************
	 * User-defined operation specified in SOIL/OCL
	 **********************************************************************/
//	public String toString(){
//		//	return ''.concat(self.toStringNumero(self.year)).concat('-').concat(let n : String = self.toStringNumero(self.month) in if (n.size = 1) then '0'.concat(n) else n endif).concat('-').concat(let n : String = self.toStringNumero(self.day) in if (n.size = 1) then '0'.concat(n) else n endif)
//		return null;
//	}

//	/**********************************************************************
//	 * User-defined operation specified in SOIL/OCL
//	 * @param numero the numero to set
//	 **********************************************************************/
//	public String toStringNumero(int numero){
//		//	TODO
//		//	return OrderedSet {1000000,10000,1000,100,10,1}->iterate(denominator : Integer; s : String = '' | let numberAsString : String = OrderedSet {'0','1','2','3','4','5','6','7','8','9'}->at(((numero / (denominator mod 10)) + 1).floor) in if ((s = '') and (numberAsString = '0')) then s.concat('0') else if numberAsString.isDefined then s.concat(numberAsString) else s endif endif)
//		return null;
//	}

	/**********************************************************************
	 * User-defined operation specified in SOIL/OCL
	 * @param t the t to set
	 **********************************************************************/
	public int yearsSince(CalendarDate t){
		if((this.month < t.month() || this.month == t.month()) && 
				this.day < t.day()){
			
			return this.year - t.year() - 1;
		}
		else{
			return this.year - t.year();
		}
		//	return if ((self.month < t.month) or ((self.month = t.month) and (self.day < t.day))) then ((self.year - t.year) - 1) else (self.year - t.year) endif

	}

	//	PRE-CONDITIONS (TODO)
	/*
	pre CalendarDateFoiInicializada4
		self.dataInicializada(t)

	 */

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	//	@Override
	//	/**********************************************************************
	//	* Object serializer
	//	**********************************************************************/
	//	public String toString()
	//	{
	//		return "CalendarDate [day=" + day + ", month=" + month + ", year=" + year + "]\n";
	//	}

	//	-------------------------------------------------------------------------------
	//	INVARIANTS (TODO)
	/*
	inv dataCumpreParametros
		self.dataDentroParametros()

	 */
}
